﻿using System;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Design;
using System.ComponentModel;
using System.Windows.Forms.Design;
using System.Collections.Generic;
using UIDesigner.Designers;
using System.ComponentModel.Design;
using SharedClasses;
using DDW;
using AFSharedLibrary;
using UIDesigner.FieldHandlers;
using System.IO;
using System.Reflection;
using UIDesigner.FieldHandlers.Bases;
using UIDesigner.DesignContainers.Bases;
using System.Diagnostics;
using System.ComponentModel.Design.Serialization;
using UIDesigner.SurfaceProperties;
using System.Windows.Forms.Design.Behavior;
using UIDesigner.DesignContainers.Glyphs;
using System.Threading;
using UIDesigner.SurfaceProperties.Templates;
using DesignerHost;
using System.Xml;
using System.Collections;
using UIDesigner.SurfaceProperties.Operations;
using UIDesigner.SurfaceProperties.Information;
using System.Text.RegularExpressions;
using UIDesigner.Editors;
using System.CodeDom;

namespace UIDesigner
{
    public enum LayoutMode
    {
        FlowLayout,
        TableLayout
    }
}

namespace UIDesigner.DesignContainers
{
    public enum GrabHandleLocation
    {
        Unknown,
        LeftMiddle,
        TopLeft,
        TopMiddle,
        TopRight,
        RightMiddle,
        BottomRight,
        BottomMiddle,
        BottomLeft,
    }

    public enum SelectionBorderLocation
    {
        Unknown,
        Top,
        Left,
        Right,
        Bottom
    }

    [Flags()]
    public enum AdornerOperation
    {
        NonSelectable = 1,
        NonMoveable = 2,
        NonResizable = 4
    }

    [Serializable()]
    public partial class ObjectControlContainer : BaseObjectControlContainer, ITemplateProvider
    {
        private Construct m_objConstruct;
        private string m_strObjectName;
        private LayoutMode m_eLayoutMode = LayoutMode.TableLayout;
        private string m_strHeader;
        private Dictionary<string, FieldSpecification> m_rgFieldSpecifications = new Dictionary<string, FieldSpecification>();
        private Label m_lblHeader;
        private Panel m_ctrlLayoutPanel;
        private bool m_bIsBusObject = false;
        private string m_strObjectType;
        private string m_strObjectNamespace;
        private string m_strPropertyName;
        private string m_strBindingSourceProperty;
        private TemplateView m_ctrlTemplateView;
        private Adorner m_objAdorner;
        private BehaviorService m_objBehaviorService;
        private ISelectionService m_objTempSelectionService;
        private System.Windows.Forms.Timer m_objResizeTimer;
        private System.Windows.Forms.Timer m_objHeaderTimer;
        private System.ComponentModel.IContainer components = null;
        private Panel m_ctrlMainPanel;
        private List<ITemplate> m_rgTemplates;
        private int m_hOverlayControl;
        private WindowsAPI.WindowProc m_fnNewWindowProc;
        private int m_fnOldWindowProc;
        private bool m_bCapture;
        private int m_nLastHeaderClick = 0;
        private bool m_bInternalResize;
        private TableLayoutPanel m_ctrlSurfaceButtonsPanel;
        private List<XmlDocument> m_rgTemplateDocuments;
        private TableLayoutPanel m_ctrlSurfaceWrapperPanel;
        private bool m_bAllInstantiated;
        private Control m_ctrlFirstTab;
        private Size m_szLargestTemplate;
        private SurfaceButtons m_rgSurfaceButtons;
        private CodeStatementCollection m_rgTemplateOptionBindings;
        private List<Control> m_rgAddedControls;

        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public Control FirstTabControl
        {
            get 
            { 
                return m_ctrlFirstTab; 
            }
        }

        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public List<Control> AddedControls
        {
            get
            {
                if (m_rgAddedControls == null)
                {
                    m_rgAddedControls = new List<Control>();
                }

                return m_rgAddedControls;
            }
        }

        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public CodeStatementCollection TemplateOptionBindings
        {
            get
            {
                if (m_rgTemplateOptionBindings == null)
                {
                    m_rgTemplateOptionBindings = new CodeStatementCollection();
                }

                return m_rgTemplateOptionBindings;
            }
        }

        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public Panel MainPanel
        {
            get { return m_ctrlMainPanel; }
        }

        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public List<ITemplate> Templates
        {
            get 
            { 
                return m_rgTemplates; 
            }
        }

        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public SurfaceButtons SurfaceButtons
        {
            get 
            {
                if (m_rgSurfaceButtons == null)
                {
                    m_rgSurfaceButtons = new SurfaceButtons();
                }

                return m_rgSurfaceButtons; 
            }
        }

        [Browsable(false)]
        public override Construct BusinessObject
        {
            get 
            {
                return m_objConstruct;
            }
        }

        [Category("Object Information"), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public string ObjectName
        {
            get
            {
                return m_strObjectName;
            }
        }

        [Category("Object Information"), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public string PropertyName
        {
            get 
            { 
                return m_strPropertyName; 
            }
            
            set 
            { 
                m_strPropertyName = value; 
            }
        }

        [Category("Object Information"), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public string BindingSourceProperty
        {
            get
            {
                return m_strBindingSourceProperty;
            }

            set
            {
                m_strBindingSourceProperty = value;
            }
        }

        [Category("Object Information"), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public string ObjectNamespace
        {
            get 
            { 
                return m_strObjectNamespace; 
            }
        }

        [Category("Object Information"), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public string ObjectType
        {
            get 
            { 
                return m_strObjectType; 
            }
        }

        [Category("Object Information"), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public bool IsBusinessObject
        {
            get 
            { 
                return m_bIsBusObject; 
            }
        }

        [Browsable(false)]
        public override string Text
        {
            get
            {
                return base.Text;
            }
            set
            {
                base.Text = value;
                Rebuild();
            }
        }

        [Editor(typeof(FieldSpecEditor), typeof(UITypeEditor))]
        [Category("Behavior"), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
        public Dictionary<string, FieldSpecification> FieldSpecifications
        {
            get 
            { 
                return m_rgFieldSpecifications; 
            }
        }

        [Category("Appearance"), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public string HeaderText
        {
            get 
            { 
                return m_strHeader; 
            }
            
            set 
            { 
                m_strHeader = value;
            }
        }

        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public Label Header
        {
            get
            {
                return m_lblHeader;
            }
        }

        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public int HeaderHeight
        {
            get
            {
                return m_lblHeader.Height + m_lblHeader.Margin.Top + m_lblHeader.Margin.Bottom + 7;
            }
        }

        [Category("Appearance"), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
        public LayoutMode LayoutMode
        {
            get 
            { 
                return m_eLayoutMode; 
            }
            
            set 
            { 
                if (m_eLayoutMode != value)
                {
                    PropertyDescriptorCollection rgProperties = TypeDescriptor.GetProperties(this);
                    PropertyDescriptor objProperty = rgProperties.Find("LayoutMode", false);
                    object objOldValue = m_eLayoutMode;

                    ComponentChangeService.OnComponentChanging(this, objProperty);

                    m_eLayoutMode = value;

                    ComponentChangeService.OnComponentChanged(this, objProperty, objOldValue, m_eLayoutMode);
                }
            }
        }

        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public Construct Construct
        {
            set 
            { 
                m_objConstruct = value;
                m_strObjectName = m_objConstruct.Name;
                m_strHeader = m_objConstruct.Name; 
            }

            get
            {
                return m_objConstruct;
            }
        }

        public ObjectControlContainer()
        {
            this.AutoScroll = true;
            m_rgTemplates = new List<ITemplate>();
        }

        protected override void OnLoad(object sender)
        {
            Form frm = this.FindForm();

            this.components = new System.ComponentModel.Container();

            m_objResizeTimer = new System.Windows.Forms.Timer(this.components);
            m_objHeaderTimer = new System.Windows.Forms.Timer(this.components);

            m_objResizeTimer.Interval = 5;
            m_objResizeTimer.Enabled = false;
            m_objResizeTimer.Tick += new EventHandler(ResizeTimerTick);

            m_objHeaderTimer.Interval = 100;
            m_objHeaderTimer.Enabled = false;
            m_objHeaderTimer.Tick += new EventHandler(HeaderTimerTick);

            m_hOverlayControl = ((Control)m_objHost.RootComponent).Parent.Handle.ToInt32();
            m_fnNewWindowProc = WindowProc;

            m_fnOldWindowProc = WindowsAPI.SetWindowLong(m_hOverlayControl, WindowsAPI.WindowLongIndex.GWL_WNDPROC, m_fnNewWindowProc);
            SubclassTracker.AddProc(m_hOverlayControl, m_fnNewWindowProc, m_fnOldWindowProc);

            m_objHost.ComponentRemoving += new ComponentEventHandler(ComponentRemoving);

            m_objHost.DesignerLoader.HandleLayoutPanelChild += new AFDesignerLoader.HandleLayoutPanelChildHandler(HandleLayoutPanelChild);

            Rebuild();

            frm.Deactivate += new EventHandler(FormDeactivate);
            frm.Leave += new EventHandler(FormLeave);
            this.Leave += new EventHandler(ObjectControlContainerLeave);
        }

        protected override void WndProc(ref Message m)
        {
            if (m_objHost != null)
            {
                if (m.Msg == (int)WindowsAPI.WindowsMessage.WM_WINDOWPOSCHANGING)
                {
                    if (this.TemplateViewShowing)
                    {
                        this.EndTemplateView();
                    }

                    if (m_objHost.SmartPanelShowing)
                    {
                        m_objHost.CloseSmartPanel();
                    }
                }
            }

            base.WndProc(ref m);
        }

        public override void RemoveTemplatedControls()
        {
            IContainer objContainer = (IContainer)m_objHost;

            foreach (ITemplate objTemplate in m_rgTemplates)
            {
                objTemplate.RemoveControls();
            }

            m_rgTemplates.Clear();

            if (m_ctrlTemplateView != null)
            {
                objContainer.Remove(m_ctrlTemplateView);
                m_ctrlTemplateView.Dispose();

                m_ctrlTemplateView = null;
            }
        }

        private void ObjectControlContainerLeave(object sender, EventArgs e)
        {
            if (m_bCapture == true)
            {
                m_ctrlTemplateView.NoClick();
                m_bCapture = false;
            }
        }

        private void FormLeave(object sender, EventArgs e)
        {
            if (m_bCapture == true)
            {
                m_ctrlTemplateView.NoClick();
                m_bCapture = false;
            }
        }

        private void FormDeactivate(object sender, EventArgs e)
        {
            if (m_bCapture == true)
            {
                m_ctrlTemplateView.NoClick();
                m_bCapture = false;
            }
        }

        private void ComponentRemoving(object sender, ComponentEventArgs e)
        {
            if (e.Component == this)
            {
                BindingSource objBindingSource = (BindingSource) m_objHost.Container.Components[this.BindingSourceProperty];

                if (objBindingSource != null)
                {
                    m_objHost.Container.Remove(objBindingSource);
                }
            }
        }

        protected override void DestroyHandle()
        {
            WindowsAPI.SetWindowLong(m_hOverlayControl, WindowsAPI.WindowLongIndex.GWL_WNDPROC, m_fnOldWindowProc);
            SubclassTracker.RemoveProc(m_fnNewWindowProc); 

            base.DestroyHandle();
        }

        protected override void OnLostFocus(EventArgs e)
        {
            base.OnLostFocus(e);
        }

        private int WindowProc(int hWnd, int uMsg, int wParam, int lParam)
        {
            if (uMsg == (int)WindowsAPI.WindowsMessage.WM_PARENTNOTIFY)
            {
                short wEvent = 0;
                short wNotUsed = 0;

                BitShift.GetHighLowWord(wParam, ref wEvent, ref wNotUsed);

                if (wEvent == (int)WindowsAPI.WindowsMessage.WM_LBUTTONDOWN)
                {
                    short x = 0;
                    short y = 0;
                    Point pt;
                    int hWndClicked;
                    Control ctrlClicked;
                    int nTick;
                    int nDblClick;

                    BitShift.GetHighLowWord(lParam, ref x, ref y);
                    pt = new Point(x, y);

                    WindowsAPI.ClientToScreen(hWnd, ref pt);
                    hWndClicked = WindowsAPI.WindowFromPoint(pt.X, pt.Y);
                    ctrlClicked = Control.FromHandle(new IntPtr(hWndClicked));

                    if (ctrlClicked == m_lblHeader)
                    {
                        if (m_bCapture == true)
                        {
                            m_ctrlTemplateView.NoClick();
                        }

                        nTick = WindowsAPI.GetTickCount();
                        nDblClick = WindowsAPI.GetDoubleClickTime();

                        if (!WindowsAPI.IsKeyPressed(WindowsAPI.VirtualKeys.VK_SHIFT) && !WindowsAPI.IsKeyPressed(WindowsAPI.VirtualKeys.VK_CONTROL))
                        {
                            if (nTick - m_nLastHeaderClick < nDblClick)
                            {
                                m_objHeaderTimer.Tag = "DoubleClick";
                            }
                            else
                            {
                                m_objHeaderTimer.Tag = "SingleClick";
                            }

                            m_objHeaderTimer.Start();

                            m_nLastHeaderClick = WindowsAPI.GetTickCount();
                        }
                    }
                    else if (ctrlClicked is TemplateView)
                    {
                        WindowsAPI.ScreenToClient(hWndClicked, ref pt);
                        m_ctrlTemplateView.OnClick(pt.X, pt.Y);

                        m_bCapture = true;
                    }
                    else if (m_bCapture == true)
                    {
                        m_ctrlTemplateView.NoClick();
                        m_bCapture = false;
                    }
                }
            }

            return WindowsAPI.CallWindowProc(m_fnOldWindowProc, hWnd, uMsg, wParam, lParam);
        }

        private void HeaderTimerTick(object sender, EventArgs e)
        {
            ISelectionService objSvc = (ISelectionService)((IServiceContainer)m_objHost).GetService(typeof(ISelectionService));
            bool bDblClick = false;
            WindowsAPI.WinMSG m = new WindowsAPI.WinMSG();
            int nMax = 0;

            if (m_ctrlMainPanel != null && m_ctrlMainPanel.Visible)
            {
                if (m_objHeaderTimer.Tag != null && m_objHeaderTimer.Tag.ToString() == "DoubleClick")
                {
                    bDblClick = true;
                }
            }

            if (objSvc.SelectionCount == 1)
            {
                object[] rgComponents = (object[])m_objSelectionService.GetSelectedComponents();
                IComponent objIComponent = (IComponent)rgComponents[0];

                if ((bDblClick && objIComponent == m_ctrlMainPanel) || objIComponent == this)
                {
                    m_objHeaderTimer.Stop();

                    while (WindowsAPI.PeekMessage(ref m, 0, (int)WindowsAPI.WindowsMessage.WM_LBUTTONUP, (int)WindowsAPI.WindowsMessage.WM_LBUTTONUP, 1) == 0)
                    {
                        nMax++;

                        if (nMax == 2000)
                        {
                            break;
                        }
                    }
                }
                else
                {
                    if (bDblClick)
                    {
                        objSvc.SetSelectedComponents(new IComponent[1] { m_ctrlMainPanel });
                    }
                    else
                    {
                        objSvc.SetSelectedComponents(new IComponent[1] { this });
                    }
                }
            }
            else
            {
                if (bDblClick)
                {
                    objSvc.SetSelectedComponents(new IComponent[1] { m_ctrlMainPanel });
                }
                else
                {
                    objSvc.SetSelectedComponents(new IComponent[1] { this });
                }
            }
        }

        protected IComponentChangeService ComponentChangeService
        {
            get
            {
                return (IComponentChangeService) m_objHost;
            }
        }

        protected bool TypeIsBusObject(ConstructedTypeNode objConstruct)
        {
            ClassNode objClass = objConstruct as ClassNode;
            
            if (objClass == null)
            {
                if (objConstruct.Name.Identifier == typeof(IBusinessObject).Name)
                {
                    return true;
                }
            }

            foreach (TypeNode objTypeNode in objClass.BaseClasses)
            {
                RequestType(objTypeNode.Identifier.GenericIdentifier, out objConstruct);

                if (objConstruct != null && TypeIsBusObject(objConstruct))
                {
                    return true;
                }
            }

            return false;
        }

        private void Rebuild()
        {
            ClassNode objClassNode;
            InterfaceNode objInterfaceNode;
            frmProgress frmProgress = new frmProgress();
            int x;
            int nCount;

            frmProgress.Show();
            frmProgress.Location = this.Parent.PointToScreen(this.Location);

            Application.DoEvents();

            Cursor.Current = Cursors.WaitCursor;

            this.Controls.Clear();

            if (this.LayoutMode == LayoutMode.TableLayout)
            {
                m_ctrlLayoutPanel = (TableLayoutPanel)m_objHost.CreateComponent(typeof(TableLayoutPanel));
            }
            else
            {
                m_ctrlLayoutPanel = (FlowLayoutPanel)m_objHost.CreateComponent(typeof(FlowLayoutPanel));
            }

            m_ctrlLayoutPanel.Dock = DockStyle.Fill;

            this.Controls.Add(m_ctrlLayoutPanel);

            if (m_strHeader != null && m_strHeader.Length > 0)
            {
                m_lblHeader = (Label)m_objHost.CreateComponent(typeof(Label));

                m_lblHeader.Visible = true;

                m_lblHeader.Height = 20;
                m_lblHeader.Dock = DockStyle.Top;
                m_lblHeader.BackColor = Color.Navy;
                m_lblHeader.ForeColor = Color.White;
                m_lblHeader.Text = m_strHeader;
                m_lblHeader.TextAlign = ContentAlignment.MiddleCenter;

                this.Controls.Add(m_lblHeader);
            }

            BaseFieldHandler.RequestType += new Handlers.RequestTypeHandler(RequestType);
            BaseFieldHandler.RequestType += new Handlers.RequestTypeHandler(RequestType);

            objClassNode = m_objConstruct.Node as ClassNode;

            Application.DoEvents();

            if (objClassNode != null)
            {
                m_bIsBusObject = TypeIsBusObject(objClassNode);
                m_strObjectType = objClassNode.Name.Identifier;
                m_strObjectNamespace = m_objConstruct.Namespace;
                m_strPropertyName = m_strObjectType;
                m_strBindingSourceProperty = m_strPropertyName + "BindingSource";

                nCount = objClassNode.Properties.Count;
                x = 1;

                foreach (PropertyNode objProperty in objClassNode.Properties)
                {
                    if (IsBrowsable(objProperty) && !IsBusObjectMember(objProperty))
                    {
                        SortedDictionary<float, IFieldHandler> rgHandlers = null;
                        FieldSpecification objSpec;

                        frmProgress.Info = "Adding default controls for \"" + objProperty.Names[0].GenericIdentifier + "\"";
                        frmProgress.Progress = (int) (((float)x) / ((float)nCount)) * 80;

                        StatusBar.Text = frmProgress.Info;
                        Application.DoEvents();
#if DEBUG
                        if (m_strObjectNamespace == "AFSharedLibrary")
                        {
                            rgHandlers = new SortedDictionary<float, IFieldHandler>();
                            rgHandlers.Add(0, (IFieldHandler)new MetaDataAttributeHandler(m_objHost));
                        }
                        else
                        {
                            rgHandlers = BaseFieldHandler.FindHandlers(this, objProperty, m_objHost);
                        }
#else
                        rgHandlers = BaseFieldHandler.FindHandlers(this, objProperty, m_objHost);
#endif
                        if (rgHandlers.Count > 0)
                        {
                            objSpec = new FieldSpecification(this, objClassNode, objProperty, rgHandlers);

                            m_rgFieldSpecifications.Add(objSpec.MemberName, objSpec);
                        }
                    }

                    x++;
                }
            }
            else
            {
                objInterfaceNode = m_objConstruct.Node as InterfaceNode;

                if (objInterfaceNode != null)
                {
                    m_bIsBusObject = TypeIsBusObject(objInterfaceNode);
                    m_strObjectType = objInterfaceNode.Name.Identifier;
                    m_strObjectNamespace = m_objConstruct.Namespace;
                    m_strPropertyName = m_strObjectType;
                    m_strBindingSourceProperty = m_strPropertyName + "BindingSource";

                    nCount = objInterfaceNode.Properties.Count;
                    x = 1;

                    foreach (InterfacePropertyNode objProperty in objInterfaceNode.Properties)
                    {
                        if (IsBrowsable(objProperty) && !IsBusObjectMember(objProperty))
                        {
                            SortedDictionary<float, IFieldHandler> rgHandlers = BaseFieldHandler.FindHandlers(this, objProperty, m_objHost);
                            FieldSpecification objSpec = new FieldSpecification(this, objInterfaceNode, objProperty, rgHandlers);

                            frmProgress.Info = "Adding default controls for \"" + objProperty.Names[0].GenericIdentifier + "\"";
                            frmProgress.Progress = (int)(((float)x) / ((float)nCount)) * 80;

                            StatusBar.Text = frmProgress.Info;
                            Application.DoEvents();

                            m_rgFieldSpecifications.Add(objSpec.MemberName, objSpec);
                        }

                        x++;
                    }
                }
            }

            frmProgress.Info = "Adding controls to canvas";
            frmProgress.Progress = 90;

            AddControls();

            frmProgress.Info = "Complete!";
            frmProgress.Progress = 100;

            for (float f = 1; f > 0; f -= .05f)
            {
                frmProgress.Opacity = f;
                Application.DoEvents();
                Thread.Sleep(5);
            }

            Thread.Sleep(500);

            frmProgress.Close();

            StatusBar.Text = "Ready";
            Cursor.Current = Cursors.Default;
        }

        public void AddBindings()
        {
            foreach (FieldSpecification objSpec in m_rgFieldSpecifications.Values)
            {
                if (objSpec.SelectedOption != null)
                {
                    IFieldHandler objHandler = objSpec.SelectedOption.FieldHandler;
                    string strOption = objSpec.SelectedOption.OptionName;

                    objHandler.AddBindings(strOption, objSpec.BoundControl, objSpec.Member, this.BindingSourceProperty);
                }
            }
        }

        private SurfacePropertiesBase SurfaceProperties
        {
            get
            {
                return m_objHost.SurfacePropertiesSet[this]; 
            }
        }

        private void RemoveControls(ControlCollection rgControls)
        {
            ArrayList rgControls2 = new ArrayList();

            foreach (Control ctrl in rgControls)
            {
                rgControls2.Add(ctrl);
            }

            foreach (Control ctrl in rgControls2)
            {
                RemoveControl(ctrl);
            }
        }

        private void RemoveControl(Control ctrl)
        {
            if (ctrl != null)
            {
                IContainer objContainer = (IContainer)m_objHost;

                ctrl.Parent.Controls.Remove(ctrl);
                objContainer.Remove(ctrl);
            }
        }

        public bool HasSurfaceControls
        {
            get
            {
                return m_ctrlMainPanel != null;
            }
        }

        public override void RemoveSurfaceControls()
        {
            Control ctrlRoot = (Control)m_objHost.RootComponent;
            IDesignerActionUIService objService = (IDesignerActionUIService)((IServiceProvider)m_objHost).GetService(typeof(IDesignerActionUIService));

            if (objService != null)
            {
                objService.HideUI(this);
            }

            if (m_ctrlSurfaceButtonsPanel != null)
            {
                RemoveControls(m_ctrlSurfaceButtonsPanel.Controls);
                RemoveControl(m_ctrlSurfaceButtonsPanel);

                m_ctrlSurfaceButtonsPanel = null;
            }

            if (m_ctrlMainPanel != null)
            {
                if (m_ctrlSurfaceWrapperPanel != null)
                {
                    Point ptLocation = m_ctrlMainPanel.Location;

                    if (m_ctrlSurfaceWrapperPanel.Controls.Contains(this))
                    {
                        m_ctrlSurfaceWrapperPanel.Controls.Remove(this);

                        ctrlRoot.Controls.Add(this);
                        this.Location = ptLocation;

                        RemoveControl(m_ctrlSurfaceWrapperPanel);  
                    }

                    m_ctrlSurfaceWrapperPanel = null;
                }

                RemoveControl(m_ctrlMainPanel);

                m_ctrlMainPanel = null;
            }

            RemoveTemplatedControls();

            if (this.SurfaceProperties.CreateProperties.CreateOptions == CreateOptions.CreateNewButton)
            {
                this.SurfaceProperties.CreateProperties.CreateOptions = CreateOptions.None;
            }

            if (this.SurfaceProperties.SaveProperties.SaveOptions == SaveOptions.SaveButton || this.SurfaceProperties.SaveProperties.SaveOptions == SaveOptions.ApplyButton || this.SurfaceProperties.SaveProperties.SaveOptions == SaveOptions.AddButton)
            {
                this.SurfaceProperties.SaveProperties.SaveOptions = SaveOptions.None;
            }

            if (this.SurfaceProperties.DeleteProperties.DeleteOptions == DeleteOptions.DeleteButton) 
            {
                this.SurfaceProperties.DeleteProperties.DeleteOptions = DeleteOptions.None; 
            }

            if (this.SurfaceProperties.ResetProperties.ResetOptions == ResetOptions.ClearButton || this.SurfaceProperties.ResetProperties.ResetOptions == ResetOptions.ResetButton)
            {
                this.SurfaceProperties.ResetProperties.ResetOptions = ResetOptions.None;
            }

            if (this.SurfaceProperties.CancelOptions == CancelOptions.Cancel || this.SurfaceProperties.CancelOptions == CancelOptions.Close)
            {
                this.SurfaceProperties.CancelOptions = CancelOptions.None;
            }
        }

        public override void HandleSurfaceProperties(DynamicEnumType objDynamicEnumType)
        {
            if (m_ctrlMainPanel == null)
            {
                SurfacePropertiesBase objSurfaceProperties = m_objHost.SurfacePropertiesSet[this];

                CreateSurfacePanel(objSurfaceProperties);
            }
        }


        public override void ApplySurfaceProperties(SurfacePropertiesBase objSelected)
        {
            SurfacePropertiesBase objSurfaceProperties = m_objHost.SurfacePropertiesSet[this];
            PropertyGrid ctrlGrid = (PropertyGrid)((IServiceProvider)m_objHost).GetService(typeof(PropertyGrid));

            objSelected.CopyTo(objSurfaceProperties);
            CreatePropertyDefaults.ApplyDefaults(objSurfaceProperties, m_objConstruct);

            CreateSurfacePanel(objSurfaceProperties);

            ctrlGrid.Invalidate();
            ctrlGrid.SelectedObject = ctrlGrid.SelectedObject;
            ctrlGrid.Refresh();
        }

        private void CreateSurfacePanel(SurfacePropertiesBase objSurfaceProperties)
        {
            SurfaceButton eButtons = objSurfaceProperties.SurfaceButtons;
            int cx = WindowsAPI.GetSystemMetrics(WindowsAPI.SystemMetricsIndex.SM_CXFIXEDFRAME);
            int cy = WindowsAPI.GetSystemMetrics(WindowsAPI.SystemMetricsIndex.SM_CYFIXEDFRAME);
            Point ptLocation = this.Location;
            Control ctrlRoot = (Control)m_objHost.RootComponent;
            LinkLabel cmdDelete = null;
            LinkLabel cmdClear = null;
            LinkLabel cmdCreateNew = null;
            LinkLabel cmdSave = null;
            LinkLabel cmdCancel = null;
            LinkLabel cmdLastLeft = null;
            LinkLabel cmdFirstRight = null;
            int nButtonCount = 0;
            int cxButtons = 0;
            int nColumn = 0;

            m_rgSurfaceButtons = new SurfaceButtons();

            if (m_ctrlSurfaceWrapperPanel == null)
            {
                m_ctrlSurfaceWrapperPanel = (TableLayoutPanel)m_objHost.CreateComponent(typeof(TableLayoutPanel), m_strPropertyName + "SurfaceWrapperPanel");
            }

            if (m_ctrlSurfaceButtonsPanel == null)
            {
                m_ctrlSurfaceButtonsPanel = (TableLayoutPanel)m_objHost.CreateComponent(typeof(TableLayoutPanel), m_strPropertyName + "SurfaceButtonsPanel");
            }
            else
            {
                foreach (Control ctrl in m_ctrlSurfaceButtonsPanel.Controls)
                {
                    ((IContainer)m_objHost).Remove(ctrl);
                }

                m_ctrlSurfaceButtonsPanel.Controls.Clear();
            }

            if ((eButtons & SurfaceButton.Delete) == SurfaceButton.Delete)
            {
                if (objSurfaceProperties.DeleteProperties.DeleteOptions == DeleteOptions.DeleteButton)
                {
                    cmdDelete = (LinkLabel)m_objHost.CreateComponent(typeof(LinkLabel), "cmd" + m_strPropertyName + "Delete");
                }
                else if (objSurfaceProperties.DeleteProperties.DeleteOptions == DeleteOptions.RemoveButton)
                {
                    cmdDelete = (LinkLabel)m_objHost.CreateComponent(typeof(LinkLabel), "cmd" + m_strPropertyName + "Remove");
                }
                else
                {
                    Debugger.Break();
                }

                m_rgSurfaceButtons.Add(new SurfaceButtonEntry(SurfaceButton.Delete, cmdDelete));
            }

            if ((eButtons & SurfaceButton.Reset) == SurfaceButton.Reset)
            {
                cmdClear = (LinkLabel)m_objHost.CreateComponent(typeof(LinkLabel), "cmd" + m_strPropertyName + "Clear");
                m_rgSurfaceButtons.Add(new SurfaceButtonEntry(SurfaceButton.Reset, cmdClear));
            }

            if ((eButtons & SurfaceButton.CreateNew) == SurfaceButton.CreateNew)
            {
                cmdCreateNew = (LinkLabel)m_objHost.CreateComponent(typeof(LinkLabel), "cmd" + m_strPropertyName + "CreateNew");
                m_rgSurfaceButtons.Add(new SurfaceButtonEntry(SurfaceButton.CreateNew, cmdCreateNew));
            }

            if ((eButtons & SurfaceButton.Save) == SurfaceButton.Save)
            {
                if (objSurfaceProperties.SaveProperties.SaveOptions == SaveOptions.SaveButton)
                {
                    cmdSave = (LinkLabel)m_objHost.CreateComponent(typeof(LinkLabel), "cmd" + m_strPropertyName + "Save");
                }
                else if (objSurfaceProperties.SaveProperties.SaveOptions == SaveOptions.AddButton)
                {
                    cmdSave = (LinkLabel)m_objHost.CreateComponent(typeof(LinkLabel), "cmd" + m_strPropertyName + "Add");
                }
                else if (objSurfaceProperties.SaveProperties.SaveOptions == SaveOptions.ApplyButton)
                {
                    cmdSave = (LinkLabel)m_objHost.CreateComponent(typeof(LinkLabel), "cmd" + m_strPropertyName + "Apply");
                }
                else
                {
                    Debugger.Break();
                }

                m_rgSurfaceButtons.Add(new SurfaceButtonEntry(SurfaceButton.Save, cmdSave));
            }

            if ((eButtons & SurfaceButton.Cancel) == SurfaceButton.Cancel)
            {
                cmdCancel = (LinkLabel)m_objHost.CreateComponent(typeof(LinkLabel), "cmd" + m_strPropertyName + "Cancel");
                m_rgSurfaceButtons.Add(new SurfaceButtonEntry(SurfaceButton.Cancel, cmdCancel));
            }

            if (m_ctrlMainPanel == null)
            {
                m_ctrlMainPanel = (Panel)m_objHost.CreateComponent(typeof(Panel), m_strPropertyName + "MainPanel");
            }

            if (this.Parent.Controls.Contains(this))
            {
                this.Parent.Controls.Remove(this);
            }
            
            foreach (SurfaceButton eButton in Enum.GetValues(typeof(SurfaceButton)))
            {
                if (eButton != SurfaceButton.None && eButton != SurfaceButton.Mask)
                {
                    if ((eButtons & eButton) == eButton)
                    {
                        nButtonCount++;
                    }
                }
            }

            // 
            // SurfaceButtonsPanel
            // 

            m_ctrlSurfaceButtonsPanel.ColumnStyles.Clear();
            m_ctrlSurfaceButtonsPanel.ColumnCount = nButtonCount;

            for (int x = 0; x < nButtonCount; x++)
            {
                m_ctrlSurfaceButtonsPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
            }

            m_ctrlSurfaceButtonsPanel.Dock = System.Windows.Forms.DockStyle.Fill;
            m_ctrlSurfaceButtonsPanel.RowCount = 1;
            m_ctrlSurfaceButtonsPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
            m_ctrlSurfaceButtonsPanel.TabIndex = 0;

            if (cmdDelete != null)
            {
                // 
                // cmdDelete
                // 

                m_ctrlSurfaceButtonsPanel.Controls.Add(cmdDelete, nColumn, 0);

                cmdDelete.AutoSize = true;
                cmdDelete.Margin = new System.Windows.Forms.Padding(0, 5, 10, 0);
                cmdDelete.TabIndex = 0;
                cmdDelete.TabStop = true;

                if (objSurfaceProperties.DeleteProperties.DeleteOptions == DeleteOptions.DeleteButton)
                {
                    cmdDelete.Text = "Delete";
                }
                else if (objSurfaceProperties.DeleteProperties.DeleteOptions == DeleteOptions.RemoveButton)
                {
                    cmdDelete.Text = "Remove";
                }

                cxButtons += cmdDelete.Width + cmdDelete.Margin.Left + cmdDelete.Margin.Right;

                cmdLastLeft = cmdDelete;
                nColumn++;
            }

            if (cmdClear != null)
            {
                // 
                // cmdClear
                // 
                m_ctrlSurfaceButtonsPanel.Controls.Add(cmdClear, nColumn, 0);

                cmdClear.AutoSize = true;
                cmdClear.Margin = new System.Windows.Forms.Padding(0, 5, 10, 0);
                cmdClear.TabIndex = 0;
                cmdClear.TabStop = true;
                cmdClear.Text = "Clear";
                cxButtons += cmdClear.Width + cmdClear.Margin.Left + cmdClear.Margin.Right;

                cmdLastLeft = cmdClear;
                nColumn++;
            }

            if (cmdCreateNew != null)
            {
                // 
                // cmdCreateNew
                // 
                m_ctrlSurfaceButtonsPanel.Controls.Add(cmdCreateNew, nColumn, 0);

                cmdCreateNew.AutoSize = true;
                cmdCreateNew.Margin = new System.Windows.Forms.Padding(0, 5, 10, 0);
                cmdCreateNew.TabIndex = 0;
                cmdCreateNew.TabStop = true;
                cmdCreateNew.Text = "Create New";
                cxButtons += cmdCreateNew.Width + cmdCreateNew.Margin.Left + cmdCreateNew.Margin.Right;

                cmdLastLeft = cmdCreateNew;
                nColumn++;
            }

            if (cmdSave != null)
            {
                nColumn++;
            }

            if (cmdCancel != null)
            {
                // 
                // cmdCancel
                // 

                m_ctrlSurfaceButtonsPanel.Controls.Add(cmdCancel, nButtonCount - 1, 0);

                cmdCancel.AutoSize = true;
                cmdCancel.Margin = new System.Windows.Forms.Padding(10, 5, 5, 0);
                cmdCancel.TabIndex = 0;
                cmdCancel.TabStop = true;
                cmdCancel.Text = "Cancel";
                cxButtons += cmdCancel.Width + cmdCancel.Margin.Left + cmdCancel.Margin.Right;

                cmdFirstRight = cmdCancel;
                nColumn--;
            }

            if (cmdSave != null)
            {
                // 
                // cmdSave
                // 

                if (cmdCancel == null)
                {
                    m_ctrlSurfaceButtonsPanel.Controls.Add(cmdSave, nButtonCount - 1, 0);
                }
                else
                {
                    m_ctrlSurfaceButtonsPanel.Controls.Add(cmdSave, nButtonCount - 2, 0);
                }

                cmdSave.AutoSize = true;
                cmdSave.Margin = new System.Windows.Forms.Padding(10, 5, 0, 0);
                cmdSave.TabIndex = 0;
                cmdSave.TabStop = true;

                if (objSurfaceProperties.SaveProperties.SaveOptions == SaveOptions.SaveButton)
                {
                    cmdSave.Text = "Save";
                }
                else if (objSurfaceProperties.SaveProperties.SaveOptions == SaveOptions.AddButton)
                {
                    cmdSave.Text = "Add";
                }
                else if (objSurfaceProperties.SaveProperties.SaveOptions == SaveOptions.ApplyButton)
                {
                    cmdSave.Text = "Apply";
                }

                cxButtons += cmdSave.Width + cmdSave.Margin.Left + cmdSave.Margin.Right;

                cmdFirstRight = cmdSave;
            }

            if (cmdLastLeft != null)
            {
                cmdLastLeft.Margin = new System.Windows.Forms.Padding(0, 5, this.Width - cxButtons + 10, 0);
                m_ctrlSurfaceButtonsPanel.Size = new Size(Math.Max(cxButtons, this.Width), cmdLastLeft.Height);
            }
            else if (cmdFirstRight != null)
            {
                cmdFirstRight.Margin = new System.Windows.Forms.Padding(this.Width - cxButtons + 10, 5, 0, 0);
                m_ctrlSurfaceButtonsPanel.Size = new Size(Math.Max(cxButtons, this.Width), cmdFirstRight.Height);
            }
            else
            {
                Debugger.Break();
            }

            if (m_ctrlSurfaceWrapperPanel.Controls.Count == 0)
            {
                // 
                // SurfaceWrappersPanel
                // 
                m_ctrlSurfaceWrapperPanel.Location = new System.Drawing.Point(3, 0);
                m_ctrlSurfaceWrapperPanel.Size = new System.Drawing.Size(this.Width + (cx * 2), (this.Height + (cy * 2)) + (m_ctrlSurfaceButtonsPanel.Height + (cy * 2)));
                m_ctrlSurfaceWrapperPanel.ColumnCount = 1;
                m_ctrlSurfaceWrapperPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
                m_ctrlSurfaceWrapperPanel.Controls.Add(m_ctrlSurfaceButtonsPanel, 0, 1);
                m_ctrlSurfaceWrapperPanel.Controls.Add(this, 0, 0);
                m_ctrlSurfaceWrapperPanel.RowCount = 2;
                m_ctrlSurfaceWrapperPanel.RowStyles.Add(new System.Windows.Forms.RowStyle());
                m_ctrlSurfaceWrapperPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30F));
                m_ctrlSurfaceWrapperPanel.TabIndex = 4;
            }

            if (m_ctrlMainPanel.Controls.Count == 0)
            {
                // 
                // MainPanel
                // 
                m_ctrlMainPanel.Controls.Add(m_ctrlSurfaceWrapperPanel);
                m_ctrlMainPanel.Location = ptLocation;
                m_ctrlMainPanel.Size = new System.Drawing.Size(m_ctrlSurfaceWrapperPanel.Width + (cx * 2), m_ctrlSurfaceWrapperPanel.Height + (cy * 2));
                m_ctrlMainPanel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
                m_ctrlMainPanel.TabIndex = 0;
            }

            this.Location = new Point(cx, cy);

            if (!ctrlRoot.Controls.Contains(m_ctrlMainPanel))
            {
                ctrlRoot.Controls.Add(m_ctrlMainPanel);
            }

            if (cmdCreateNew != null)
            {
                CreateTemplates();
                ShowTemplateView();
            }
        }

        private void CreateTemplates()
        {
            m_rgTemplates.Clear();

            if (this.SurfaceProperties.CreateProperties.CreateOptions == CreateOptions.CreateNewButton)
            {
                CreateProperties objInfo = this.SurfaceProperties.CreateProperties;
                int x = 1;

                if (objInfo.ConstructorOptions == ConstructorOptions.OptionsPanel)
                {
                    m_rgTemplates.Add(new CreateOptionsTemplate(m_objHost, objInfo)); 

                    foreach (SurfaceConstructorInfo objConstructor in objInfo.ConstructorInfos)
                    {
                        CreateOptionTemplate objCreateOptionTemplate = new CreateOptionTemplate(m_objHost, objInfo, x);

                        objCreateOptionTemplate.UseErrorProvider = m_bUseErrorProvider;
                        objCreateOptionTemplate.StatusBar = this.StatusBar;
                        objCreateOptionTemplate.Construct = this.Construct;
                        objCreateOptionTemplate.BusObjectsLocation = m_strBusObjectsLocation;

                        objConstructor.PanelIndex = x;

                        m_rgTemplates.Add(objCreateOptionTemplate);
                        x++;
                    }
                }
                else if (this.SurfaceProperties.CreateProperties.ConstructorOptions == ConstructorOptions.DefaultConstructor)
                {
                    // todo
                }
            }
        }

        public bool HasTemplates
        {
            get
            {
                return m_rgTemplates.Count > 0;
            }
        }

        private void HandleLayoutPanelChild(TableLayoutPanel ctrlPanel, Control ctrlChild)
        {
            Regex objRegex = new Regex(@"^(?<col>\d+?),(?<row>\d+?)$");
            Match objMatch;

            if (ctrlChild.Tag == null && !(ctrlChild.Tag is string))
            {
                Debugger.Break();
                return;
            }

            objMatch = objRegex.Match((string)ctrlChild.Tag);

            if (objMatch.Success)
            {
                int nCol = int.Parse(objMatch.Groups["col"].Value);
                int nRow = int.Parse(objMatch.Groups["row"].Value);

                ctrlPanel.Controls.Add(ctrlChild, nCol, nRow);
            }
            else
            {
                Debugger.Break();
            }
        }

        public void OnShowDesignerWindow()
        {
            if (m_rgTemplateDocuments != null && m_rgTemplateDocuments.Count > 0)
            {
                ArrayList rgErrors = new ArrayList();
                CreateProperties objProperties = this.SurfaceProperties.CreateProperties;
                int x = 1;

                Application.DoEvents();
                m_rgTemplates = new List<ITemplate>();

                foreach (XmlDocument objDocument in m_rgTemplateDocuments)
                {
                    ITemplate objTemplate = (ITemplate)m_objHost.DesignerLoader.Deserialize(objDocument, rgErrors);
                    CreateOptionsTemplate objCreateOptionsTemplate = objTemplate as CreateOptionsTemplate;
                    CreateOptionTemplate objCreateOptionTemplate = objTemplate as CreateOptionTemplate;

                    if (objCreateOptionsTemplate != null)
                    {
                        objCreateOptionsTemplate.Host = m_objHost;
                        objCreateOptionsTemplate.CreateProperties = objProperties;
                    }
                    else if (objCreateOptionTemplate != null)
                    {
                        objCreateOptionTemplate.Host = m_objHost;
                        objCreateOptionTemplate.CreateProperties = objProperties;
                        objCreateOptionTemplate.Index = x;
                        objCreateOptionTemplate.StatusBar = this.StatusBar;
                        objCreateOptionTemplate.Construct = this.Construct;
                        objCreateOptionTemplate.BusObjectsLocation = m_strBusObjectsLocation; 

                        x++;
                    }

                    objTemplate.Reset();

                    m_rgTemplates.Add(objTemplate);
                }
            }
        }

        public override void OnFlush()
        {
            if (m_ctrlTemplateView != null && !m_bAllInstantiated)
            {
                if (m_objAdorner != null)
                {
                    IDesignerActionUIService objService = (IDesignerActionUIService)((IServiceProvider)m_objHost).GetService(typeof(IDesignerActionUIService));

                    if (objService != null)
                    {
                        objService.HideUI(this);
                    }

                    m_objHost.SuppressGlyph = true;

                    EndTemplateView();
                }

                m_ctrlTemplateView.InstantiateAll();
                m_objHost.SuppressGlyph = false;

                m_bAllInstantiated = true;
            }
        }

        public void PreShowCodeWindow()
        {
            OnFlush();
        }

        public void SaveTemplates()
        {
            if (m_ctrlTemplateView != null)
            {
                frmDesignerMain frmMain = (frmDesignerMain)this.FindForm();
                Control ctrlRoot = (Control)m_objHost.RootComponent;

                m_rgTemplateDocuments = new List<XmlDocument>();

                // gets in the way of our Code Window (don't know why)

                foreach (ITemplate objTemplate in m_ctrlTemplateView.Templates)
                {
                    IComponent objComponent = objTemplate as IComponent;
                    XmlDocument objDocument;

                    if (objComponent != null)
                    {
                        if (objComponent.Site == null)
                        {
                            objComponent.Site = new AFDesignSite(m_objHost, objTemplate.TemplateName);
                        }

                        objDocument = m_objHost.DesignerLoader.Serialize(objComponent);
                        m_rgTemplateDocuments.Add(objDocument);
                    }
                }

                frmMain.SuppressCodeUpdate = true;

                RemoveControls(m_ctrlTemplateView);
                ctrlRoot.Controls.Remove(m_ctrlTemplateView);

                frmMain.SuppressCodeUpdate = false;

                m_ctrlTemplateView = null;
            }
        }

        public void OnShowCodeWindow()
        {
            if (m_objTempSelectionService != null)
            {
                Control ctrlRoot = (Control)m_objHost.RootComponent;

                m_objTempSelectionService.SetSelectedComponents(new IComponent[1] { ctrlRoot });

                try
                {
                    if (m_objAdorner != null)
                    {
                        EndTemplateView();
                    }

                    SaveTemplates();
                }
                catch (Exception ex)
                {
                    Debugger.Break();
                }
            }
        }

        public void Test()
        {
            if (m_ctrlTemplateView != null)
            {
                ArrayList rgErrors = new ArrayList();
                frmDesignerMain frmMain = (frmDesignerMain)this.FindForm();
                Control ctrlRoot = (Control)m_objHost.RootComponent;
                List<XmlDocument> rgDocuments = new List<XmlDocument>();
                PropertyGrid ctrlGrid = (PropertyGrid)((IServiceContainer)m_objHost).GetService(typeof(PropertyGrid));
                ToolBoxPanel ctrlToolbox = (ToolBoxPanel)((IServiceContainer)m_objHost).GetService(typeof(ToolBoxPanel));
                PropertyGridPanel ctrlGridPanel = (PropertyGridPanel)ctrlGrid.Parent;
                List<IComponent> rgComponents = new List<IComponent>();

                frmMain.FormMainMenu.Enabled = false;
                ctrlGrid.Hide();
                ctrlToolbox.Hide();
                m_objHost.SuppressGlyph = true;

                foreach (ITemplate objTemplate in m_ctrlTemplateView.Templates)
                {
                    IComponent objComponent = objTemplate as IComponent;
                    XmlDocument objDocument;

                    if (objComponent != null)
                    {
                        if (objComponent.Site == null)
                        {
                            objComponent.Site = new AFDesignSite(m_objHost, objTemplate.TemplateName);
                        }

                        objDocument = m_objHost.DesignerLoader.Serialize(objComponent);

                        rgDocuments.Add(objDocument);
                    }
                }

                frmMain.SuppressCodeUpdate = true;

                RemoveControls(m_ctrlTemplateView);
                ctrlRoot.Controls.Remove(m_ctrlTemplateView);

                frmMain.SuppressCodeUpdate = false;

                m_ctrlTemplateView = null;

                foreach (XmlDocument objDocument in rgDocuments)
                {
                    ITemplate objTemplate = (ITemplate) m_objHost.DesignerLoader.Deserialize(objDocument, rgErrors); 
                }

                frmMain.FormMainMenu.Enabled = true;
                ctrlGrid.Show();
                ctrlToolbox.Show();
                m_objHost.SuppressGlyph = false;
            }
        }

        public void RemoveControls()
        {
            RemoveControls(this);
        }

        public void RemoveControls(Control ctrlParent)
        {
            IContainer objContainer = (IContainer)m_objHost;

            foreach (Control ctrlControl in ctrlParent.Controls)
            {
                RemoveControls(ctrlControl);
                objContainer.Remove(ctrlControl);

                ctrlControl.Dispose();
            }

            objContainer.Remove(ctrlParent);
            ctrlParent.Dispose();
        }

        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public Rectangle ProviderBounds
        {
            get
            {
                if (m_ctrlMainPanel != null)
                {
                    Rectangle rcProvider = m_ctrlMainPanel.Bounds;
                    Size sz = m_ctrlMainPanel.Size;

                    sz.Width = Math.Max(m_szLargestTemplate.Width + 10, sz.Width);
                    sz.Height = Math.Max(m_szLargestTemplate.Height + 10, sz.Height);

                    rcProvider = new Rectangle(m_ctrlMainPanel.Location, sz);

                    return rcProvider;
                }
                else
                {
                    Rectangle rcProvider = this.Bounds;
                    Size sz = this.Size;

                    sz.Width = Math.Max(m_szLargestTemplate.Width + 10, sz.Width);
                    sz.Height = Math.Max(m_szLargestTemplate.Height + 10, sz.Height);

                    rcProvider = new Rectangle(this.Location, this.Size);

                    return rcProvider;
                }
            }
        }

        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public Rectangle TemplateBounds
        {
            get
            {
                return new Rectangle(new Point(0, 0), this.TemplateSize); 
            }
        }

        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public Size TemplateSize
        {
            get
            {
                Size sz = TemplateView.CalcCanvasSize(m_szLargestTemplate);

                return sz;
            }
        }

        private void OnTemplateResize(ITemplate objTemplate, Rectangle rc)
        {
            if (rc.Width > m_szLargestTemplate.Width)
            {
                m_szLargestTemplate.Width = rc.Width;
            }

            if (rc.Height > m_szLargestTemplate.Height)
            {
                m_szLargestTemplate.Height = rc.Height;
            }
        }

        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public bool TemplateViewShowing
        {
            get
            {
                if (m_ctrlTemplateView == null)
                {
                    return false;
                }
                else if (m_ctrlTemplateView.Parent != null && m_ctrlTemplateView.Visible)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }

        public void ShowTemplateView()
        {
            Control ctrlRoot = (Control)m_objHost.RootComponent;
            Point ptLocation = m_ctrlMainPanel.Location;
            bool bShowUI = false;
            IDesignerActionUIService objService = (IDesignerActionUIService)((IServiceProvider)m_objHost).GetService(typeof(IDesignerActionUIService));

            m_ctrlMainPanel.Visible = false;

            if (m_ctrlTemplateView == null)
            {
                m_ctrlTemplateView = (TemplateView)m_objHost.CreateComponent(typeof(TemplateView));
                m_ctrlTemplateView.OnTemplateResize += new TemplateView.OnTemplateResizeHandler(OnTemplateResize);
                m_ctrlTemplateView.Location = ptLocation;
                m_ctrlTemplateView.Size = new Size(m_ctrlMainPanel.Width, m_ctrlMainPanel.Height);
                m_ctrlTemplateView.ObjectControlContainer = this;
                m_ctrlTemplateView.Templates = m_rgTemplates;

                m_ctrlTemplateView.HandleDestroyed += new EventHandler(TemplateViewHandleDestroyed);
            }
            else
            {
                m_ctrlTemplateView.Location = ptLocation;

                objService.HideUI(this);
                bShowUI = true;
            }

            ctrlRoot.Controls.Add(m_ctrlTemplateView);

            WindowsAPI.SetWindowPos(m_ctrlTemplateView.Handle.ToInt32(), WindowsAPI.SWPInsertFlags.HWND_TOP, 0, 0, 0, 0, WindowsAPI.SWPFlags.SWP_NOMOVE | WindowsAPI.SWPFlags.SWP_NOSIZE);

            m_objBehaviorService = (BehaviorService)((IServiceContainer)m_objHost).GetService(typeof(BehaviorService));
            m_objTempSelectionService = (ISelectionService)((IServiceContainer)m_objHost).GetService(typeof(ISelectionService));

            m_objTempSelectionService.SetSelectedComponents(new IComponent[1] { m_ctrlTemplateView });
            m_objTempSelectionService.SelectionChanged += new EventHandler(OnSelectionChanged);
            m_ctrlTemplateView.Resize += new EventHandler(TemplateViewResize);

            if (bShowUI)
            {
                objService.ShowUI(m_ctrlTemplateView);
            }

            HandleAdorners(m_ctrlTemplateView, AdornerOperation.NonMoveable);
        }

        private void TemplateViewHandleDestroyed(object sender, EventArgs e)
        {
            m_bCapture = false;
        }

        public void CloseTemplateView()
        {
            IDesignerActionUIService objService = (IDesignerActionUIService)((IServiceProvider)m_objHost).GetService(typeof(IDesignerActionUIService));
            Control ctrlRoot = (Control)m_objHost.RootComponent;

            objService.HideUI(m_ctrlTemplateView);

            Application.DoEvents();

            m_objAdorner.Glyphs.Clear();
            m_objBehaviorService.Adorners.Remove(m_objAdorner);

            m_objAdorner = null;

            m_ctrlMainPanel.Visible = true;
            m_objTempSelectionService.SetSelectedComponents(new IComponent[1] { this });

            ctrlRoot.Controls.Remove(m_ctrlTemplateView);
        }

        public void EndTemplateView()
        {
            IDesignerActionUIService objService = (IDesignerActionUIService)((IServiceProvider)m_objHost).GetService(typeof(IDesignerActionUIService));
            Control ctrlRoot = (Control)m_objHost.RootComponent;

            objService.HideUI(m_ctrlTemplateView);

            Application.DoEvents();

            m_objAdorner.Glyphs.Clear();
            m_objBehaviorService.Adorners.Remove(m_objAdorner);

            m_objAdorner = null;

            m_ctrlMainPanel.Visible = true;
            m_objTempSelectionService.SetSelectedComponents(new IComponent[1] { this });

            ctrlRoot.Controls.Remove(m_ctrlTemplateView);

            objService.ShowUI(this);
        }

        private void ResizeTimerTick(object sender, EventArgs e)
        {
            SmartTagGlyph objGlyph = m_objHost.SmartTagGlyph;

            m_objResizeTimer.Stop();

            if (m_bInternalResize)
            {
                m_objHost.SuppressGlyphRemoval = true;

                objGlyph.Move();

                m_objTempSelectionService.SetSelectedComponents(null);
                m_objTempSelectionService.SetSelectedComponents(new IComponent[1] { m_ctrlTemplateView });

                m_objHost.SuppressGlyphRemoval = false;
            }
            else
            {
                m_objTempSelectionService.SetSelectedComponents(null);
                m_objTempSelectionService.SetSelectedComponents(new IComponent[1] { m_ctrlTemplateView });
            }
        }

        private void TemplateViewResize(object sender, EventArgs e)
        {
            if (m_ctrlTemplateView.InternalResize)
            {
                m_bInternalResize = true;
            }

            if (m_objHost.SmartTagGlyph != null)
            {
                m_objResizeTimer.Start();
            }
        }

        private void OnSelectionChanged(object sender, EventArgs e)
        {
            foreach (IComponent objComponent in m_objTempSelectionService.GetSelectedComponents())
            {
                if (objComponent == m_ctrlTemplateView)
                {
                    HandleAdorners(m_ctrlTemplateView, AdornerOperation.NonMoveable);
                }
            }
        }

        private void HandleAdorners(Control ctrl, AdornerOperation eOperation)
        {
            if (m_objAdorner == null)
            {
                m_objAdorner = new Adorner();
                m_objBehaviorService.Adorners.Add(m_objAdorner);
            }
            else
            {
                m_objAdorner.Glyphs.Clear();
            }

            foreach (Adorner objAdorner in m_objBehaviorService.Adorners)
            {
                if (objAdorner != m_objAdorner)
                {
                    List<Glyph> rgGlyphs = new List<Glyph>();
                    bool bInvalidate = false;

                    foreach (Glyph objGlyph in objAdorner.Glyphs)
                    {
                        if (!(objGlyph is ControlBodyGlyph))
                        {
                            rgGlyphs.Add(objGlyph);
                        }
                    }

                    foreach (Glyph objGlyph in rgGlyphs)
                    {
                        if (objGlyph.GetType().Name == "GrabHandleGlyph")
                        {
                            GrabHandleLocation eLocation = GetGrabHandleLocation(objGlyph, ctrl);

                            if ((eOperation & AdornerOperation.NonSelectable) == AdornerOperation.NonSelectable)
                            {
                                m_objAdorner.Glyphs.Add(new OverlayGlyph(m_objBehaviorService, m_ctrlTemplateView, objGlyph));
                            }
                            else
                            {
                                if ((eOperation & AdornerOperation.NonMoveable) == AdornerOperation.NonMoveable)
                                {
                                    switch (eLocation)
                                    {
                                        case GrabHandleLocation.TopLeft:
                                        case GrabHandleLocation.TopMiddle:
                                        case GrabHandleLocation.TopRight:
                                        case GrabHandleLocation.LeftMiddle:
                                        case GrabHandleLocation.BottomLeft:
                                        case GrabHandleLocation.Unknown:

                                            m_objAdorner.Glyphs.Add(new OverlayGlyph(m_objBehaviorService, m_ctrlTemplateView, objGlyph));
                                            bInvalidate = true;
                                            break;

                                    }
                                }

                                if ((eOperation & AdornerOperation.NonResizable) == AdornerOperation.NonResizable)
                                {
                                    switch (eLocation)
                                    {
                                        case GrabHandleLocation.RightMiddle:
                                        case GrabHandleLocation.BottomRight:
                                        case GrabHandleLocation.BottomMiddle:

                                            m_objAdorner.Glyphs.Add(new OverlayGlyph(m_objBehaviorService, m_ctrlTemplateView, objGlyph));
                                            bInvalidate = true;
                                            break;
                                    }
                                }
                            }
                        }
                        else if (objGlyph.GetType().Name == "ContainerSelectorGlyph")
                        {
                            if ((eOperation & AdornerOperation.NonSelectable) == AdornerOperation.NonSelectable)
                            {
                                m_objAdorner.Glyphs.Add(new OverlayGlyph(m_objBehaviorService, m_ctrlTemplateView, objGlyph));
                                bInvalidate = true;
                            }
                            else if ((eOperation & AdornerOperation.NonMoveable) == AdornerOperation.NonMoveable)
                            {
                                m_objAdorner.Glyphs.Add(new OverlayGlyph(m_objBehaviorService, m_ctrlTemplateView, objGlyph));
                                bInvalidate = true;
                            }
                        }
                        else if (objGlyph.GetType().Name == "SelectionBorderGlyph")
                        {
                            SelectionBorderLocation eLocation = GetSelectionBorderLocation(objGlyph, ctrl);

                            if ((eOperation & AdornerOperation.NonSelectable) == AdornerOperation.NonSelectable)
                            {
                                objAdorner.Glyphs.Remove(objGlyph);
                            }
                            else
                            {
                                if ((eOperation & AdornerOperation.NonMoveable) == AdornerOperation.NonMoveable)
                                {
                                    switch (eLocation)
                                    {
                                        case SelectionBorderLocation.Left:
                                        case SelectionBorderLocation.Top:

                                            m_objAdorner.Glyphs.Add(new OverlayGlyph(m_objBehaviorService, m_ctrlTemplateView, objGlyph));
                                            bInvalidate = true;
                                            break;
                                    }
                                }

                                if ((eOperation & AdornerOperation.NonResizable) == AdornerOperation.NonResizable)
                                {
                                    switch (eLocation)
                                    {
                                        case SelectionBorderLocation.Right:
                                        case SelectionBorderLocation.Bottom:

                                            m_objAdorner.Glyphs.Add(new OverlayGlyph(m_objBehaviorService, m_ctrlTemplateView, objGlyph));
                                            bInvalidate = true;
                                            break;
                                    }
                                }
                            }
                        }
                    }

                    if (bInvalidate)
                    {
                        objAdorner.Invalidate();
                    }
                }
            }

            m_objBehaviorService.Invalidate();
        }

        private SelectionBorderLocation GetSelectionBorderLocation(Glyph objGlyph, Control ctrl)
        {
            Point ptParent = ctrl.Parent.Location;
            Point ptControlCenter = new Point(ctrl.Left + (ctrl.Width / 2), ctrl.Top + (ctrl.Height / 2));
            Rectangle rc = objGlyph.Bounds;
            int cx = WindowsAPI.GetSystemMetrics(WindowsAPI.SystemMetricsIndex.SM_CXEDGE);
            int cy = WindowsAPI.GetSystemMetrics(WindowsAPI.SystemMetricsIndex.SM_CYEDGE);

            ptParent.X = -ptParent.X;
            ptParent.Y = -ptParent.Y;

            rc.Offset(ptParent);

            if (rc.Bottom == ctrl.Top - 1)
            {
                if (rc.Bottom == ctrl.Bottom + cy)
                {
                    if (rc.Left == ctrl.Left - cx)
                    {
                        return SelectionBorderLocation.Left;
                    }
                    else if (rc.Right == ctrl.Right + cx)
                    {
                        return SelectionBorderLocation.Right;
                    }
                }
                else if ((rc.Left == ctrl.Left - cx) && (rc.Right == ctrl.Right + cx))
                {
                    return SelectionBorderLocation.Top;
                }

                return SelectionBorderLocation.Top;
            }
            else if (rc.Top == ctrl.Bottom + 1)
            {
                if ((rc.Left == ctrl.Left - cx) && (rc.Right == ctrl.Right + cx))
                {
                    return SelectionBorderLocation.Bottom;
                }
            }
            else if (rc.Left == ctrl.Left - cx)
            {
                if (rc.Bottom == ctrl.Bottom + cy)
                {
                    return SelectionBorderLocation.Left;
                }
            }
            else if (rc.Right == ctrl.Right + cx)
            {
                if (rc.Bottom == ctrl.Bottom + cy)
                {
                    return SelectionBorderLocation.Right;
                }
            }

            return SelectionBorderLocation.Unknown;
        }

        private GrabHandleLocation GetGrabHandleLocation(Glyph objGlyph, Control ctrl)
        {
            Point ptParent = ctrl.Parent.Location;
            Point ptControlCenter = new Point(ctrl.Left + (ctrl.Width / 2), ctrl.Top + (ctrl.Height / 2));
            Rectangle rc = objGlyph.Bounds;
            int cx = WindowsAPI.GetSystemMetrics(WindowsAPI.SystemMetricsIndex.SM_CXEDGE);
            int cy = WindowsAPI.GetSystemMetrics(WindowsAPI.SystemMetricsIndex.SM_CYEDGE); 

            ptParent.X = -ptParent.X;
            ptParent.Y = -ptParent.Y;

            rc.Offset(ptParent);

            if (rc.Right == ctrl.Left + cx)
            {
                if (rc.Bottom == ctrl.Top + cy)
                {
                    return GrabHandleLocation.TopLeft;
                }
                else if (rc.Top == ctrl.Bottom - cy)
                {
                    return GrabHandleLocation.BottomLeft;
                }
                else if (rc.Top + (rc.Height / 2) == ptControlCenter.Y)
                {
                    return GrabHandleLocation.LeftMiddle;
                }
            }
            else if (rc.Bottom == ctrl.Top + cy)
            {
                if (rc.Left + (rc.Width / 2) == ptControlCenter.X)
                {
                    return GrabHandleLocation.TopMiddle;
                }
                else if (rc.Left == ctrl.Right - cx)
                {
                    return GrabHandleLocation.TopRight; 
                }
            }
            else if (rc.Top == ctrl.Bottom - cy)
            {
                if (rc.Left == ctrl.Right - cx)
                {
                    return GrabHandleLocation.BottomRight; 
                }
                else if (rc.Left + (rc.Width / 2) == ptControlCenter.X)
                {
                    return GrabHandleLocation.BottomMiddle;
                }
            }
            else if ((rc.Left == ctrl.Right - cx) && (rc.Top + (rc.Height / 2) == ptControlCenter.Y))
            {
                return GrabHandleLocation.RightMiddle;
            }

            return GrabHandleLocation.Unknown;
        }

        private void AddControls()
        {
            LayoutManager objLayoutManager;

            if (m_eLayoutMode == LayoutMode.TableLayout)
            {
                LayoutStyle eLayoutStyle;
                int nHighAlignment = 0;
                List<char> rgMnemonics = new List<char>();
                LayoutItem objLayoutItem;
                int nTabIndex = 0;
                int nWidth = 0;
                int nHeight = 0;
                TableLayoutPanel ctrlLayoutPanel = (TableLayoutPanel)m_ctrlLayoutPanel;

                objLayoutManager = new LayoutManager(ctrlLayoutPanel, m_objHost);

                foreach (FieldSpecification objSpec in m_rgFieldSpecifications.Values)
                {
                    if (objSpec.SelectedOption != null)
                    {
                        IFieldHandler objHandler = objSpec.SelectedOption.FieldHandler;
                        string strOption = objSpec.SelectedOption.OptionName;
                        int nAlignment;
                        Size szControl;

                        objHandler.NegotiateLayout(strOption, ctrlLayoutPanel, objSpec.Member, LayoutMode.TableLayout, ref nTabIndex, out eLayoutStyle, out nAlignment, out szControl);

                        Debug.Assert(eLayoutStyle != LayoutStyle.Unassigned);
                        Debug.Assert(nAlignment != -1);

                        objSpec.TabIndex = nTabIndex - 1;
                        objSpec.LayoutStyle = eLayoutStyle;
                        objSpec.ControlSize = szControl;

                        if (eLayoutStyle == LayoutStyle.HorizontalDoubleCellAligned)
                        {
                            if (nAlignment > nHighAlignment)
                            {
                                nHighAlignment = nAlignment;
                            }
                        }
                    }
                }

                foreach (FieldSpecification objSpec in m_rgFieldSpecifications.Values)
                {
                    if (objSpec.SelectedOption != null)
                    {
                        IFieldHandler objHandler = objSpec.SelectedOption.FieldHandler;
                        string strOption = objSpec.SelectedOption.OptionName;
                        TableLayoutPanel ctrlInnerPanel;
                        Size sz = objSpec.ControlSize;

                        if (objSpec.ControlSize == Size.Empty)
                        {
                            objLayoutItem = objLayoutManager.AddRow(objSpec.LayoutStyle, nHighAlignment, true);
                        }
                        else
                        {
                            if (m_bUseErrorProvider)
                            {
                                ErrorProvider objErrorProvider = new ErrorProvider();

                                objSpec.ControlSize = new Size(objSpec.ControlSize.Width + objErrorProvider.Icon.Width + 2, objSpec.ControlSize.Height);
                            }

                            objLayoutItem = objLayoutManager.AddRow(objSpec.LayoutStyle, nHighAlignment, true, objSpec.ControlSize);
                        }

                        ctrlInnerPanel = objLayoutItem.InnerPanel;
                        objSpec.BoundControl = objHandler.AddDefaultControls(ctrlInnerPanel, objSpec.Member, objSpec.TabIndex, objLayoutItem.TableLayoutPanelCellPositions, rgMnemonics);
                        objSpec.BoundControl.Size = sz;

                        this.AddedControls.Add(objSpec.BoundControl);

                        if (objSpec.TabIndex == 0)
                        {
                            m_ctrlFirstTab = objSpec.BoundControl;
                        }

                        foreach (Control ctrl in ctrlInnerPanel.Controls)
                        {
                            TableLayoutPanelCellPosition objPos = ctrlInnerPanel.GetPositionFromControl(ctrl);
                            ctrl.Tag = objPos.ToString();
                        }
                    }
                }

                foreach (TableLayoutPanel ctrlRow in ctrlLayoutPanel.Controls)
                {
                    if (ctrlRow.Width > nWidth)
                    {
                        nWidth = ctrlRow.Width + GetPaddingWidth(ctrlRow);
                    }

                    nHeight += ctrlRow.Height + GetPaddingHeight(ctrlRow);
                }

                nHeight += m_lblHeader.Height; 

                this.Width = nWidth;
                this.Height = nHeight;
            }

            AddBindings();
        }

        public List<XmlDocument> TemplateDocuments
        {
            get 
            {
                if (m_rgTemplateDocuments == null)
                {
                    m_rgTemplateDocuments = new List<XmlDocument>();
                }

                return m_rgTemplateDocuments;
            }
        }
    }
}
